//#########################################################
//#
//# Titre : 	UTILITAIRES (MAIN) TP1 LINUX Automne 13
//#			SIF-1015 - Systeme d'exploitation
//#			Universite du Quebec a� Trois-Rivieres
//#
//# Auteur : 	Francois Meunier
//#	Date :	Septembre 2013
//#
//# Langage : 	ANSI C on LINUX 
//#
//#########################################################

#include "gestionListeChaineeCHAT.h"

//Pointeur de tete de liste
struct noeud* head;
//Pointeur de queue de liste pour ajout rapide
struct noeud* queue;

//Semaphore de gestion de la tete de la liste
sem_t headSem;
//Semaphore de gestion de la queue de la liste
sem_t tailSem;
//Semaphore de gestion du texte affiché
sem_t texteSem;

//Pointeur vers l'écran d'affichage
WINDOW* contentscr;

//Descripteur du serveur
int trxServerFD;

//Identifiant unique de chaque usager
int idMembre = 0;

int main(int argc, char* argv[])
{

	WINDOW* stdscr = initscr();
	
	if(stdscr != NULL)
	{
		//Valide qu'on peut utiliser les couleurs sur le terminal
		Has_colors();

		//Valide que les couleurs sont pretes a etre utilisée
		Start_color();

		//Initialisation des couleurs
		Init_color_pairs();

		//Initilalisation des propriétés de la fenetre standard qui sert de cadre
		box(stdscr, '|', '=');
		mvprintw(0, (COLS - 49)/2, "Serveur de gestion de chat, (ctrl+c) pour quitter");
		refresh();

		//Initialisation de la fenetre du contenu qui servira a afficher l'information 
		contentscr = newwin(LINES-2, COLS-3, 1, 2);
		scrollok(contentscr, TRUE);//active le scroll automatique
		wattron(contentscr, COLOR_PAIR(GREEN_ON_BLACK));//L'affichage sera en vert

		//Initialisation des pointeurs
		head = NULL;
		queue = NULL;

		//Initialisation des sémaphores
		Sem_init(&headSem, 0, 1);
		Sem_init(&tailSem, 0, 1);
		Sem_init(&texteSem, 0, 1);

		//Pointeurs sur la laiste de threads
		struct threadNode* mainHeadThread = NULL;
		struct threadNode* mainTailThread = NULL;

		char message[MESSAGE_SIZE];
		memset(message, '\0', MESSAGE_SIZE);

		int serverLength, clientLength;
		struct sockaddr_in serverAddress, clientAddress;

		trxServerFD = Socket(AF_INET, SOCK_STREAM, 0);
		serverLength = sizeof(serverAddress);
		serverAddress.sin_family = AF_INET;
		serverAddress.sin_addr.s_addr = inet_addr(SERVER_ADDRESS);

		if(bindAvailablePort(trxServerFD, &serverAddress, serverLength) == 0)
		{
			listen(trxServerFD, MAX_CLIENT);
			
			sprintf(message, "\nServeur en attente de clients sur %s:%i\n\n", SERVER_ADDRESS, serverAddress.sin_port);
			waddstr(contentscr, message);
			wrefresh(contentscr);

			clientLength = sizeof(clientAddress);

			while(1)
			{
				int *clientFD = (int*)malloc(sizeof(int));
				*clientFD = accept(trxServerFD, (struct sockaddr*)&clientAddress, (socklen_t*)&clientLength);

				if(*clientFD > 0)
				{

					//Cree le nouveau noeud dans la liste de threads
					initThreadNode(&mainHeadThread, &mainTailThread);

					Pthread_create(&(mainTailThread->thread), NULL, &executeTransCHAT, clientFD);
				}
			}

			//Attente de la terminaison des threads et liberation de la mémoire de chaque noeud
			struct threadNode* ittThread = mainHeadThread;
			struct threadNode* tempThread = NULL;
			while (ittThread != NULL)
			{
				Pthread_join(ittThread->thread, NULL);

				tempThread = ittThread->suivant;

				free(ittThread);

				ittThread = tempThread;
			}

			//Fermeture du socket
			close(trxServerFD);

			//Destruction des semaphores et liberation de la mémoire de chaque noeud
			struct noeud* ittNoeud = head;
			struct noeud* tempNoeud = NULL;
			while (ittNoeud != NULL)
			{
				Sem_destroy(&(ittNoeud->sem));

				tempNoeud = ittNoeud->suivant;

				free(ittNoeud);		

				ittNoeud = tempNoeud;
			}

			//Destruction des sémaphores
			Sem_destroy(&headSem);
			Sem_destroy(&tailSem);
			Sem_destroy(&texteSem);

			//Message de fermeture
			waddstr(contentscr, "\n\nArret du serveur...");
			wrefresh(contentscr);
			sleep(2);
		}
		else
		{
			waddstr(contentscr, "\n\n>>> Erreur au bind du socket!\n\n");
			wrefresh(contentscr);
			sleep(2);
		}

		//Supprime la fenetre d'affichage
		Delwin(contentscr);

		//Retourne le terminal a son etat d'origine
		endwin();

		//Fin du programme
		exit(EXIT_SUCCESS);
	}
	else
	{
		printf("\n\n>>> Erreur a l'initialisation de l'ecran!\n\n");

		exit(EXIT_FAILURE);
	}
}

